package cn.blt.security.auth.service.impl;

import cn.blt.security.auth.entity.LoginUserDetails;
import cn.blt.security.auth.entity.dto.UserDTO;
import cn.blt.exception.SaaSException;
import cn.blt.security.auth.mapper.SysUserMapper;
import cn.blt.security.auth.service.SysUserService;
import cn.blt.utils.JwtUtils;
import cn.blt.utils.MD5Utlis;
import cn.blt.security.auth.entity.vo.UserVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import cn.blt.security.auth.entity.SysUser;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import cn.blt.common.Result;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 登录表 服务实现类
 * @author run
 * @since 2022-07-27
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService, UserDetailsService {

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private AuthenticationManager authenticationManager;

    /**
     * 注册
     * @param user 用户
     * @return {@link Result}
     */
    @Override
    public Result register(SysUser user) {
        String password = MD5Utlis.getMD5(user.getPassword());
        log.info("MD5加密密码 => {}",password);
        user.setPassword(password);
        baseMapper.insert(user);
        return Result.ok();
    }

    /**
     * 登录
     * @param userDTO 用户
     * @return {@link Result}
     */
    @Override
    public Result login(UserDTO userDTO) {
        try{
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword());
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            if (Objects.isNull(authenticate)) throw new RuntimeException("未授权!");
            LoginUserDetails loginUserDetails = (LoginUserDetails) authenticate.getPrincipal();
            SysUser user = loginUserDetails.getUser();
            UserVo userVo = new UserVo();
            String userId = user.getId() + "";
            userVo.setId(userId);
            userVo.setUserAcct(userDTO.getUsername());
            String token = JwtUtils.geneJsonWebToken(userVo);
            log.info("token生成 => {}",token);
            redisTemplate.opsForValue().set("login:"+ userId,JSONObject.toJSONString(user),12,TimeUnit.HOURS);
            log.info("redis set key = {} and value = {}","login:"+ userId,user);
            return Result.ok(token);
        }catch(Exception e){
            log.error(e.getMessage());
            return Result.error(e.getMessage());
        }
    }

    /**
     * 当前登录人信息
     * @param token 令牌
     * @return {@link Result}
     */
    @Override
    public Result info(String token) {
        try{
            Long userId = JwtUtils.getUserId(token);
            String json = redisTemplate.opsForValue().get("login:"+ userId);
            log.info("Redis 根据 id={} 获取登陆人信息 => {}",userId,json);
            if (StringUtils.isEmpty(json)){
                SysUser user = baseMapper.selectById(userId);
                log.info("Mysql 根据 id={} 获取登陆人信息 => {}",userId,json);
                redisTemplate.opsForValue().set("login:"+ userId,JSONObject.toJSONString(user),12,TimeUnit.HOURS);
                return Result.ok(user);
            }
            SysUser user = JSONObject.parseObject(json, SysUser.class);
            return Result.ok(user);
        }catch(Exception e){
            log.error(e.getMessage());
            return Result.error(e.getMessage());
        }
    }

    /**
     * 加载用户用户名
     * @param usernmae usernmae
     * @return {@link UserDetails}
     * @throws UsernameNotFoundException 用户名没有发现异常
     */
    @Override
    public UserDetails loadUserByUsername(String usernmae) throws UsernameNotFoundException {
        try{
            LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysUser::getUserAcct,usernmae);
            SysUser user = baseMapper.selectOne(wrapper);
            if (Objects.isNull(user)) throw new SaaSException("账号不存在！");
            if (user.getStatus() == 0) throw new SaaSException("账号已被禁用！");
            LoginUserDetails loginUserDetails = new LoginUserDetails();
            loginUserDetails.setUser(user);
            return loginUserDetails;
        }catch(Exception e){
            log.error("loadUserByUsername => " + e.getMessage());
            throw new SaaSException(e.getMessage());
        }
    }
}
